package com.bg.rpc.zk;

import com.bg.rpc.constant.Constant;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CountDownLatch;

/**
 * @Auther: zhengshunzhi
 * @Date: 2018/8/24 16:13
 * @Description: /**
 * 连接ZK注册中心，创建服务注册目录
 */
public class ServiceRegistry {
    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistry.class);

    //计数器
    private static final CountDownLatch latch = new CountDownLatch(1);

    //zk对象
    private static ZooKeeper zk;

    public ServiceRegistry() {
    }

    /**
     * 功能描述: 注册zk
     *
     * @param: data
     * @return:
     * @auther: bonree
     * @date: 2018/8/29 10:11
     */
    public void register(String data)  {
        try {
            if (data != null) {
                //连接zk的方法
                connectServer();
                if (zk != null) {
                    if (zk.exists(Constant.ZK_REGISTRY_PATH,false) ==null){
                        //创建持久根节点
                        zk.create(Constant.ZK_REGISTRY_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                    }
                    //如果zk不为空则创建zk节点和存储数据
                    createNode(Constant.ZK_DATA_PATH, data);
                }
            }
        }catch (Exception e){
            LOGGER.error("zk注册节点失败：",e);
        }

    }

    /**
     * 功能描述:连接zk的方法
     *
     * @return: ZooKeeper
     * @auther: bonree
     * @date: 2018/8/29 10:12
     */
    private void connectServer() {
        try {
            //1:zk的连接地址和端口(可升级为集群版本)
            //2:zk连接超时时间
            //3:监听接口
            zk = new ZooKeeper(Constant.ZK_CONNECT, Constant.ZK_SESSION_TIMEOUT, new Watcher() {
                public void process(WatchedEvent event) {
                    // 判断是否已连接ZK,连接后计数器递减.保证原子性
                    if (event.getState() == Event.KeeperState.SyncConnected) {
                        latch.countDown();
                    }
                }
            });

            // 若计数器不为0,则等待.
            //计数器为0则表示已经成功连接
            latch.await();
        } catch (Exception e) {
            LOGGER.error("zk连接失败：", e);
        }
    }

   /**
    * 功能描述: 创建zk节点和存储数据
    * @param: dir
    * @return: data
    * @auther: bonree
    * @date: 2018/8/29 10:21
    */
    private void createNode(String dir, String data) {
        try {
            //将数据转为二进制
            byte[] bytes = data.getBytes();
            //参数1：节点路径
            //参数2：数据
            //参数3：节点权限
            //参数4：节点类型(临时/永久) 这里为临时节点
            String path = zk.create(dir, bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            LOGGER.info("create zookeeper node ({} => {})", path, data);
        } catch (Exception e) {
            LOGGER.error("zk节点创建失败：", e);
        }
    }
}
